/*
    SDL - Simple DirectMedia Layer
    Partial implementation of SDL library (originally written by
    Sam Lantinga <slouken@libsdl.org>) for the particular purpose to support
    Prequengine (http://code.google.com/p/prequengine/) on BlackBerry(tm)
    tablets and smartphones.

    Copyright (C) 2013  xlamsp

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

    xlamsp@gmail.com
*/

#ifndef SDL_AUDIO_H_
#define SDL_AUDIO_H_

#include "SDL_stdinc.h"
#include "SDL_error.h"

/**
 * When filling in the desired audio spec structure,
 * - 'desired->freq' should be the desired audio frequency in samples-per-second.
 * - 'desired->format' should be the desired audio format.
 * - 'desired->samples' is the desired size of the audio buffer, in samples.
 *     This number should be a power of two, and may be adjusted by the audio
 *     driver to a value more suitable for the hardware.  Good values seem to
 *     range between 512 and 8096 inclusive, depending on the application and
 *     CPU speed.  Smaller values yield faster response time, but can lead
 *     to underflow if the application is doing heavy processing and cannot
 *     fill the audio buffer in time.  A stereo sample consists of both right
 *     and left channels in LR ordering.
 *     Note that the number of samples is directly related to time by the
 *     following formula:  ms = (samples*1000)/freq
 * - 'desired->size' is the size in bytes of the audio buffer, and is
 *     calculated by SDL_OpenAudio().
 * - 'desired->silence' is the value used to set the buffer to silence,
 *     and is calculated by SDL_OpenAudio().
 * - 'desired->callback' should be set to a function that will be called
 *     when the audio device is ready for more data.  It is passed a pointer
 *     to the audio buffer, and the length in bytes of the audio buffer.
 *     This function usually runs in a separate thread, and so you should
 *     protect data structures that it accesses by calling SDL_LockAudio()
 *     and SDL_UnlockAudio() in your code.
 * - 'desired->userdata' is passed as the first parameter to your callback
 *     function.
 *
 * @note The calculated values in this structure are calculated by SDL_OpenAudio()
 *
 */
typedef struct SDL_AudioSpec {
    int    freq;        /**< DSP frequency -- samples per second */
    Uint16 format;      /**< Audio data format */
    Uint8  channels;    /**< Number of channels: 1 mono, 2 stereo */
    Uint8  silence;     /**< Audio buffer silence value (calculated) */
    Uint16 samples;     /**< Audio buffer size in samples (power of 2) */
    Uint16 padding;     /**< Necessary for some compile environments */
    Uint32 size;        /**< Audio buffer size in bytes (calculated) */
    /**
     *  This function is called when the audio device needs more data.
     *
     *  @param[out] stream  A pointer to the audio data buffer
     *  @param[in]  len     The length of the audio buffer in bytes.
     *
     *  Once the callback returns, the buffer will no longer be valid.
     *  Stereo samples are stored in a LRLRLR ordering.
     */
    void (*callback)(void *userdata, Uint8 *stream, int len);
    void  *userdata;
} SDL_AudioSpec;

/**
 *  @name Audio format flags
 *  defaults to LSB byte order
 */
/*@{*/
#define AUDIO_U8        0x0008  /**< Unsigned 8-bit samples */
#define AUDIO_S8        0x8008  /**< Signed 8-bit samples */
#define AUDIO_U16LSB    0x0010  /**< Unsigned 16-bit samples */
#define AUDIO_S16LSB    0x8010  /**< Signed 16-bit samples */
#define AUDIO_U16MSB    0x1010  /**< As above, but big-endian byte order */
#define AUDIO_S16MSB    0x9010  /**< As above, but big-endian byte order */
#define AUDIO_U16       AUDIO_U16LSB
#define AUDIO_S16       AUDIO_S16LSB
/*@}*/


/** A structure to hold a set of audio conversion filters and buffers */
typedef struct SDL_AudioCVT {
    int needed;                 /**< Set to 1 if conversion possible */
    Uint16 src_format;          /**< Source audio format */
    Uint16 dst_format;          /**< Target audio format */
    double rate_incr;           /**< Rate conversion increment */
    Uint8 *buf;                 /**< Buffer to hold entire audio data */
    int    len;                 /**< Length of original audio buffer */
    int    len_cvt;             /**< Length of converted audio buffer */
    int    len_mult;            /**< buffer must be len*len_mult big */
    double len_ratio;           /**< Given len, final size is len*len_ratio */
    void (*filters[10])(struct SDL_AudioCVT *cvt, Uint16 format);
    int filter_index;           /**< Current audio conversion function */
} SDL_AudioCVT;


/**
 * This function takes a source format and rate and a destination format
 * and rate, and initializes the 'cvt' structure with information needed
 * by SDL_ConvertAudio() to convert a buffer of audio data from one format
 * to the other.
 *
 * @return This function returns 0, or -1 if there was an error.
 */
extern int SDL_BuildAudioCVT(SDL_AudioCVT *cvt,
        Uint16 src_format, Uint8 src_channels, int src_rate,
        Uint16 dst_format, Uint8 dst_channels, int dst_rate);

/**
 * Once you have initialized the 'cvt' structure using SDL_BuildAudioCVT(),
 * created an audio buffer cvt->buf, and filled it with cvt->len bytes of
 * audio data in the source format, this function will convert it in-place
 * to the desired format.
 * The data conversion may expand the size of the audio data, so the buffer
 * cvt->buf should be allocated after the cvt structure is initialized by
 * SDL_BuildAudioCVT(), and should be cvt->len*cvt->len_mult bytes long.
 */
extern int SDL_ConvertAudio(SDL_AudioCVT *cvt);

/**
 * This takes two audio buffers of the playing audio format and mixes
 * them, performing addition, volume adjustment, and overflow clipping.
 * The volume ranges from 0 - 128, and should be set to SDL_MIX_MAX_VOLUME
 * for full audio volume.  Note this does not change hardware volume.
 * This is provided for convenience -- you can mix your own audio data.
 */
extern void SDL_MixAudio(Uint8 *dst, const Uint8 *src, Uint32 len, int volume);

/**
 * @name Audio Locks
 * The lock manipulated by these functions protects the callback function.
 * During a LockAudio/UnlockAudio pair, you can be guaranteed that the
 * callback function is not running.  Do not call these from the callback
 * function or you will cause deadlock.
 */
/*@{*/
extern void SDL_LockAudio(void);
extern void SDL_UnlockAudio(void);
/*@}*/

/* Function to calculate the size and silence for a SDL_AudioSpec */
extern void SDL_CalculateAudioSpec(SDL_AudioSpec *spec);

#endif /* SDL_AUDIO_H_ */

